package com.easyjava.builder;

import com.easyjava.bean.Constants;
import com.easyjava.bean.FieldInfo;
import com.easyjava.bean.TableInfo;
import com.easyjava.utils.StringUtils;
import com.sun.org.apache.xpath.internal.operations.And;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName BuildMapperXml
 * @Date 2024/7/4  16:24
 **/
public class BuildMapperXml {
    private static final Logger logger = LoggerFactory.getLogger(BuildMapperXml.class);

    private static final String BASE_COLUMN_LIST = "base_column_list";

    private static final String BASE_QUERY_CONDITION = "base_query_condition";

    private static final String QUERY_CONDITION = "query_condition";
    private static final String BASE_QUERY_CONDITION_EXTEND = "base_query_condition_extend";


    private static String stringQuery = "";

    private static void extracted(TableInfo tableInfo, BufferedWriter bufferedWriter, StringBuilder insertField) throws IOException {
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (fieldInfo.getAutoIncrement()){
                continue;
            }
            insertField.append(fieldInfo.getFieldName()).append(",");
        }
        String insertStr = insertField.substring(0, insertField.lastIndexOf(","));
        bufferedWriter.write("\t\tINSERT INTO " + tableInfo.getTableName() + "(" + insertStr + ") values");
        bufferedWriter.newLine();
        bufferedWriter.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">");
        bufferedWriter.newLine();
        StringBuilder insertProperty = new StringBuilder();
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (fieldInfo.getAutoIncrement()){
                continue;
            }
            insertProperty.append("#{item.").append(fieldInfo.getPropertyName()).append("}").append(",");
        }
        String str = insertProperty.substring(0, insertProperty.lastIndexOf(","));
        bufferedWriter.write("\t\t\t(" + str + ")");
        bufferedWriter.newLine();
        bufferedWriter.write("\t\t</foreach>");
        bufferedWriter.newLine();
    }

    private static void extracted(TableInfo tableInfo, BufferedWriter bufferedWriter) throws IOException {
        bufferedWriter.write("\t\tINSERT INTO " + tableInfo.getTableName());
        bufferedWriter.newLine();
        bufferedWriter.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
        bufferedWriter.newLine();
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (fieldInfo.getAutoIncrement()){
                continue;
            }
            bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + "!=null\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + ",");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t</if>");
            bufferedWriter.newLine();
        }
        bufferedWriter.write("\t\t</trim>");
        bufferedWriter.newLine();
        bufferedWriter.write("\t\t<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
        bufferedWriter.newLine();

        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if (fieldInfo.getAutoIncrement()){
                continue;
            }
            bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + "!=null\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t\t#{bean." + fieldInfo.getPropertyName() + "},");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t</if>");
            bufferedWriter.newLine();
        }
        bufferedWriter.write("\t\t</trim>");
        bufferedWriter.newLine();
    }


    public static void execute(TableInfo tableInfo) {
        File folder = new File(Constants.PATH_MAPPER_XML);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String className = tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;
        File file = new File(folder, className + ".xml");
        try {
            OutputStream outputStream = Files.newOutputStream(file.toPath());
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "utf8");
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            bufferedWriter.newLine();
            bufferedWriter.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
            bufferedWriter.newLine();
            bufferedWriter.write("<mapper namespace=\"" + Constants.PACKAGE_MAPPER + "." + className + "\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<!--实体映射-->");
            bufferedWriter.newLine();
            String poClass = Constants.PACKAGE_PO + "." + tableInfo.getBeanName();
            bufferedWriter.write("\t<resultMap id=\"base_result_map\" type=\"" + poClass + "\">");
            bufferedWriter.newLine();
            FieldInfo idField = null;
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for (Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()) {
                if ("PRIMARY".equals(entry.getKey())) {
                    List<FieldInfo> fieldInfoList = entry.getValue();
                    if (fieldInfoList.size() == 1) {
                        idField = fieldInfoList.get(0);
                        break;
                    }
                }
            }
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                bufferedWriter.write("\t\t<!-- " + fieldInfo.getComment() + "-->");
                bufferedWriter.newLine();
                String key = "";
                if (idField != null && fieldInfo.getPropertyName().equals(idField.getPropertyName())) {
                    key = "id";
                } else {
                    key = "result";
                }
                bufferedWriter.write("\t\t<" + key + " column=\"" + fieldInfo.getFieldName() + "\" property=\"" + fieldInfo.getPropertyName() + "\"/>");
                bufferedWriter.newLine();
            }
            bufferedWriter.write("\t</resultMap>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();
            //通用查询列
            bufferedWriter.write("\t<!--通用查询列-->");
            bufferedWriter.newLine();
            String base_column_list = "base_column_list";
            bufferedWriter.write("\t<sql id =\"" + base_column_list + "\">");
            bufferedWriter.newLine();
            StringBuilder columnBuilder = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                columnBuilder.append(fieldInfo.getFieldName()).append(",");
            }
            String columnBuilderStr = columnBuilder.substring(0, columnBuilder.lastIndexOf(","));
            bufferedWriter.write("\t\t" + columnBuilderStr);
            bufferedWriter.newLine();
            bufferedWriter.write("\t</sql>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            bufferedWriter.write("\t<!--基础查询条件-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<sql id=\"" + BASE_QUERY_CONDITION + "\">");
            bufferedWriter.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                if (ArrayUtils.contains(Constants.SQL_STRING_TYPE, fieldInfo.getSqlType())) {
                    stringQuery = " and query." + fieldInfo.getPropertyName() + " != ''";
                }
                bufferedWriter.write("\t\t<if test=\"query." + fieldInfo.getPropertyName() + " != null" + stringQuery + "\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\tand id = #{query." + fieldInfo.getPropertyName() + "}");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t</if>");
                bufferedWriter.newLine();
            }
            bufferedWriter.write("\t</sql>");
            bufferedWriter.newLine();

            bufferedWriter.newLine();
            bufferedWriter.write("\t<!--扩展的查询条件-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<sql id=\"" + BASE_QUERY_CONDITION_EXTEND + "\">");
            bufferedWriter.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldExtendList()) {
                String andWhere = "";
                if (ArrayUtils.contains(Constants.SQL_STRING_TYPE, fieldInfo.getSqlType())) {
                    andWhere = "and " + fieldInfo.getFieldName() + " like concat('%',#{query." + fieldInfo.getPropertyName() + "},'%')";
                } else if (ArrayUtils.contains(Constants.SQL_DATE_TYPE, fieldInfo.getSqlType()) || ArrayUtils.contains(Constants.SQL_DATE_TIME_TYPE, fieldInfo.getSqlType())) {
                    if (fieldInfo.getPropertyName().endsWith(Constants.SUFFIX_QUERY_TIME_START)) {
                        andWhere = "<![CDATA[ and " + fieldInfo.getFieldName() + ">=str_to_date(#{query." + fieldInfo.getPropertyName() + "},'%Y-%m-%d') ]]>";
                    } else if (fieldInfo.getPropertyName().endsWith(Constants.SUFFIX_QUERY_TIME_END)) {
                        andWhere = "<![CDATA[ and " + fieldInfo.getFieldName() + "< date_sub(str_to_date(#{query." + fieldInfo.getPropertyName() + "},'%Y-%m-%d')," + "interval - 1 day) ]]>";
                    }
                }
                bufferedWriter.write("\t\t<if test=\"query." + fieldInfo.getPropertyName() + " != null" + " and query." + fieldInfo.getPropertyName() + " != ''" + "\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t" + andWhere);
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t</if>");
                bufferedWriter.newLine();
            }
            bufferedWriter.write("\t</sql>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();
            bufferedWriter.write("\t<!--通用查询条件-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<sql id=\"" + QUERY_CONDITION + "\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t<where>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t<include refid = \"" + BASE_QUERY_CONDITION + "\"/>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t<include refid = \"" + BASE_QUERY_CONDITION_EXTEND + "\"/>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t</where>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t</sql>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            //查询列表
            bufferedWriter.write("\t<!--查询列表-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<select id=\"selectList\" resultMap=\"base_result_map\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\tSELECT");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t<include refid=\"" + BASE_COLUMN_LIST + "\"/>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\tFROM");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t" + tableInfo.getTableName());
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t<include refid=\"" + QUERY_CONDITION + "\"/>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t<if test=\"query.orderBy!=null\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\torder by ${query.orderBy}");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t</if>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t<if test=\"query.simplePage!=null\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\tlimit #{query.simplePage.start},#{query.simplePage.end}");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t</if>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t</select>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            //查询数量
            bufferedWriter.write("\t<!--查询数量-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<select id=\"selectCount\" resultType=\"java.lang.Integer\">");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\tSELECT");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\tcount(1)");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\tFROM");
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t\t" + tableInfo.getTableName());
            bufferedWriter.newLine();
            bufferedWriter.write("\t\t<include refid=\"" + QUERY_CONDITION + "\"/>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t</select>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            //插入
            bufferedWriter.write("\t<!--插入（匹配有值的字段）-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<insert id=\"insert\" parameterType=\"" + poClass + "\">");
            bufferedWriter.newLine();
            FieldInfo autoIncrement = null;
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                if (fieldInfo.getAutoIncrement() != null && fieldInfo.getAutoIncrement()) {
                    autoIncrement = fieldInfo;
                    break;
                }
            }
            if (autoIncrement != null) {
                bufferedWriter.write("\t\t<selectKey keyProperty=\"bean." + autoIncrement.getFieldName() + "\" resultType=\"" + autoIncrement.getJavaType() + "\" order=\"AFTER\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\tSELECT LAST_INSERT_ID()");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t</selectKey>");
            }
            bufferedWriter.newLine();
            extracted(tableInfo, bufferedWriter);
            bufferedWriter.write("\t</insert>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();

            //插入或更新
            bufferedWriter.write("\t<!--插入或更新（匹配有值的字段）-->");
            bufferedWriter.newLine();
            bufferedWriter.write("\t<insert id=\"insertOrUpdate\" parameterType=\"" + poClass + "\">");
            bufferedWriter.newLine();

            extracted(tableInfo, bufferedWriter);

            bufferedWriter.write("\t\ton DUPLICATE key update");
            bufferedWriter.newLine();

            Map<String, String> keyTempMap = new HashMap<>();
            for (Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()) {
                List<FieldInfo> fieldInfoList = entry.getValue();
                for (FieldInfo fieldInfo : fieldInfoList) {
                    if (fieldInfo.getAutoIncrement()){
                        continue;
                    }
                    keyTempMap.put(fieldInfo.getFieldName(), fieldInfo.getFieldName());
                }
            }

            bufferedWriter.write("\t\t<trim prefix=\"\" suffix=\"\" suffixOverrides=\",\">");
            bufferedWriter.newLine();
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
//                if (keyTempMap.get(fieldInfo.getFieldName()) != null) {
//                    continue;
//                }
                bufferedWriter.write("\t\t\t<if test=\"bean." + fieldInfo.getPropertyName() + "!=null\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t\t" + fieldInfo.getFieldName() + "=VALUES(" + fieldInfo.getFieldName() + "),");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t</if>");
                bufferedWriter.newLine();
            }
            bufferedWriter.write("\t\t</trim>");
            bufferedWriter.newLine();
            bufferedWriter.write("\t</insert>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();


            //批量插入
            bufferedWriter.write("\t<insert id=\"insertBatch\" parameterType=\"" + poClass + "\">");
            bufferedWriter.newLine();
            StringBuilder insertField = new StringBuilder();
            extracted(tableInfo, bufferedWriter, insertField);
            bufferedWriter.write("\t</insert>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();


            //批量修改
            bufferedWriter.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\"" + poClass + "\">");
            bufferedWriter.newLine();
            StringBuilder insertField1 = new StringBuilder();
            extracted(tableInfo, bufferedWriter, insertField1);
            bufferedWriter.write("\t\ton duplicate key update");
            bufferedWriter.newLine();
            StringBuilder insertField2 = new StringBuilder();
            for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
                if (fieldInfo.getAutoIncrement()){
                    continue;
                }
                insertField2.append(fieldInfo.getFieldName()).append("=VALUES(").append(fieldInfo.getFieldName()).append("),");
            }
            String str = insertField2.substring(0, insertField2.lastIndexOf(","));
            bufferedWriter.write("\t\t" + str);
            bufferedWriter.newLine();
            bufferedWriter.write("\t</insert>");
            bufferedWriter.newLine();
            bufferedWriter.newLine();


            //根据PrimaryKey获取对象
            for(Map.Entry<String,List<FieldInfo>> entry : keyIndexMap.entrySet()){
                List<FieldInfo> keyFieldInfoList = entry.getValue();
                Integer index = 0;
                StringBuilder methodName = new StringBuilder();
                StringBuffer paramsName = new StringBuffer();
                for (FieldInfo fieldInfo:keyFieldInfoList){
                    index++;
                    methodName.append(StringUtils.uperCaseFirstLetter(fieldInfo.getPropertyName()));
                    paramsName.append(fieldInfo.getFieldName()+"=#{" + fieldInfo.getPropertyName()+"} ");
                    if (index < keyFieldInfoList.size()){
                        methodName.append("And");
                        paramsName.append("and ");
                    }
                }
                bufferedWriter.newLine();
                bufferedWriter.newLine();
                bufferedWriter.write("\t<!--根据" + methodName + "查询-->");
                bufferedWriter.newLine();
                bufferedWriter.write("\t<select id=\"selectBy" + methodName + "\" resultMap=\"base_result_map\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\tselect");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t<include refid=\""+BASE_COLUMN_LIST+"\"/>");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\tfrom " +tableInfo.getTableName());
                bufferedWriter.newLine();
                bufferedWriter.write("\t\twhere " + paramsName);
                bufferedWriter.newLine();
                bufferedWriter.write("\t</select>");
                bufferedWriter.newLine();
                bufferedWriter.newLine();

                bufferedWriter.write("\t<!--根据" + methodName + "删除-->");
                bufferedWriter.newLine();
                bufferedWriter.write("\t<delete id=\"deleteBy" + methodName+ "\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\tdelete from");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t"+tableInfo.getTableName());
                bufferedWriter.newLine();
                bufferedWriter.write("\t\twhere " + paramsName);
                bufferedWriter.newLine();
                bufferedWriter.write("\t</delete>");
                bufferedWriter.newLine();
                bufferedWriter.newLine();


                bufferedWriter.write("\t<!--根据" + methodName + "更新-->");
                bufferedWriter.newLine();
                bufferedWriter.write("\t<update id=\"updateBy"+ methodName+ "\" parameterType=\""+poClass+"\">");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\tUPDATE "+tableInfo.getTableName());
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t<set>");
                bufferedWriter.newLine();
                for (FieldInfo fieldInfo:tableInfo.getFieldList()){
                    bufferedWriter.write("\t\t\t<if test=\"bean."+fieldInfo.getPropertyName()+"!=null\">");
                    bufferedWriter.newLine();
                    bufferedWriter.write("\t\t\t\t"+fieldInfo.getFieldName()+"=#{bean."+fieldInfo.getPropertyName()+"},");
                    bufferedWriter.newLine();
                    bufferedWriter.write("\t\t\t</if>");
                    bufferedWriter.newLine();
                }
                bufferedWriter.write("\t\t</set>");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\twhere");
                bufferedWriter.newLine();
                bufferedWriter.write("\t\t\t"+paramsName);
                bufferedWriter.newLine();
                bufferedWriter.write("\t</update>");
                bufferedWriter.newLine();
                bufferedWriter.newLine();
            }


            bufferedWriter.write("</mapper>");
            bufferedWriter.flush();
        } catch (Exception e) {
            logger.error("创建mapperXml失败", e);
        }
    }
}
